import { defineStore } from 'pinia';
import { getRoot, setRoot, makeInitialData, patchRoot } from './useStorage';
import type { StorageModel, Bookmark, Group } from '../types/model';
import { uid } from '../utils/uid';
import { useSettings } from './useSettings';
import { isHttpUrl } from '../utils/validators';
import { debounce } from '../utils/debounce';
import { LOGI, LOGW, LOGE } from '../../../shared/log.js';

interface DragSnapshot {
  bookmarks: Bookmark[];
  groups: Group[];
}

function nextOrder(list: Bookmark[]): number {
  const max = list.reduce((m, b) => Math.max(m, b.order ?? 0), 0);
  return Math.ceil((max + 10) / 10) * 10;
}

// 将响应式数组转为普通数组，避免写入 storage 时被序列化为对象
function plain(list: Bookmark[]): Bookmark[] {
  return Array.isArray(list) ? list.map(b => ({ ...b })) : [];
}

export const useBookmarks = defineStore('bookmarks', {
  state: () => ({
    inited: false,
    bookmarks: [] as Bookmark[],
    groups: [] as Group[],
    // 错误提示文案统一
    errorMsg: '⚠️ 保存失败，已回滚',
    _initRetry: 0 as number,
  }),
  getters: {
    byGroup: (s) => (groupId?: string) => s.bookmarks
      .filter(b => (groupId ? b.groupId === groupId : !b.groupId || b.groupId === 'default'))
      .sort((a, b) => (a.order ?? 0) - (b.order ?? 0)),
  },
  actions: {
    async init() {
      if (this.inited) return;
      const ok = await this._loadFromStorageWithRetry();
      if (!ok) {
        // 最终失败也不置 inited，避免假初始化导致后续不再尝试
        try{ (window as any).gceToast?.('⚠️ 无法读取本地数据，请稍后重试'); }catch{}
        LOGW('BM', '初始化失败：无法读取本地数据');
        return;
      }
      this.inited = true;
    },
    async reload() {
      await this._loadFromStorageWithRetry();
    },

    async _loadFromStorageWithRetry(max = 5, delayMs = 300): Promise<boolean> {
      for (let i = 0; i < max; i++) {
        const root = await getRoot();
        if (root) {
          const r = root as StorageModel;
          this.bookmarks = Array.isArray(r.bookmarks) ? r.bookmarks : [];
          this.groups = Array.isArray(r.groups) ? r.groups : [{ id: 'default', name: '未分组', order: 10 }];
          return true;
        }
        await new Promise(res => setTimeout(res, delayMs));
      }
      LOGW('BM', '多次重试后仍未获取到 root');
      return false;
    },

    // 分组
    async addGroup(name: string, icon?: string) {
      const last = this.groups.length ? (this.groups[this.groups.length - 1].order ?? 0) : 0;
      const g: Group = { id: uid('gp-'), name, icon, order: last + 10 } as Group;
      let root = await getRoot();
      if (!root) { await setRoot(makeInitialData()); root = await getRoot(); }
      const r = root as StorageModel;
      const next = [...(Array.isArray(r.groups) ? r.groups : []), g];
      try {
        await patchRoot({ groups: next } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const st = useSettings();
          await setRoot(makeInitialData());
          await patchRoot({ groups: next, settings: (st as any).settings } as Partial<StorageModel>);
          LOGW('BM', 'storage_unavailable：已重建存储并重试写入 groups(keep settings)');
        } else { throw e; }
      }
      this.groups.push(g);
      LOGI('BM', 'addGroup', name);
    },
    async updateGroup(id: string, patch: Partial<Group>) {
      let root = await getRoot();
      if (!root) { await setRoot(makeInitialData()); root = await getRoot(); }
      const r = root as StorageModel;
      const next = (Array.isArray(r.groups) ? r.groups : []).map(g => g.id === id ? { ...g, ...patch } : g);
      try {
        await patchRoot({ groups: next } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const st = useSettings();
          await setRoot(makeInitialData());
          await patchRoot({ groups: next, settings: (st as any).settings } as Partial<StorageModel>);
          LOGW('BM', 'storage_unavailable：已重建存储并重试写入 groups(update, keep settings)');
        } else { throw e; }
      }
      this.groups = this.groups.map(g => g.id === id ? { ...g, ...patch } : g);
    },
    async renameGroup(id: string, name: string) {
      await this.updateGroup(id, { name });
    },
    async removeGroup(id: string) {
      let root = await getRoot();
      if (!root) { await setRoot(makeInitialData()); root = await getRoot(); }
      const r = root as StorageModel;
      r.bookmarks = Array.isArray(r.bookmarks) ? r.bookmarks : [];
      r.groups = Array.isArray(r.groups) ? r.groups : [];
      const has = r.bookmarks.some(b => (b.groupId ?? 'default') === id);
      if (has) {
        throw new Error('请先转移该组中的链接');
      }
      const next = r.groups.filter(g => g.id !== id);
      try {
        await patchRoot({ groups: next } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const st = useSettings();
          await setRoot(makeInitialData());
          await patchRoot({ groups: next, settings: (st as any).settings } as Partial<StorageModel>);
          LOGW('BM', 'storage_unavailable：已重建存储并重试写入 groups(remove, keep settings)');
        } else { throw e; }
      }
      this.groups = this.groups.filter(g => g.id !== id);
    },

    // 书签 CRUD
    async addBookmark(data: Omit<Bookmark, 'id' | 'createdAt' | 'updatedAt' | 'order'>) {
      if (!isHttpUrl(data.url)) throw new Error('URL 必须以 http(s):// 开头');
      const now = Date.now();
      const groupId = data.groupId ?? 'default';
      const order = nextOrder(this.byGroup(groupId));
      const b: Bookmark = { id: uid('bm-'), order, createdAt: now, updatedAt: now, ...data } as Bookmark;
      let root = await getRoot();
      if (!root) { await setRoot(makeInitialData()); root = await getRoot(); }
      const r = root as StorageModel;
      const next = [...(Array.isArray(r.bookmarks) ? r.bookmarks : []), b];
      try {
        await patchRoot({ bookmarks: next, groups: this.groups.slice() } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const st = useSettings();
          await setRoot(makeInitialData());
          await patchRoot({ bookmarks: next, groups: this.groups.slice(), settings: (st as any).settings } as Partial<StorageModel>);
          LOGW('BM', 'storage_unavailable：已重建存储并重试写入 bookmarks(add, keep settings)');
        } else { throw e; }
      }
      this.bookmarks.push(b);
      LOGI('BM', 'addBookmark', data.title);
    },
    async updateBookmark(id: string, patch: Partial<Bookmark>) {
      if (patch.url && !isHttpUrl(patch.url)) throw new Error('URL 必须以 http(s):// 开头');
      const now = Date.now();
      let root = await getRoot();
      if (!root) { await setRoot(makeInitialData()); root = await getRoot(); }
      const r = root as StorageModel;
      const next = (Array.isArray(r.bookmarks) ? r.bookmarks : []).map(b => b.id === id ? { ...b, ...patch, updatedAt: now } : b);
      try {
        await patchRoot({ bookmarks: next } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const st = useSettings();
          await setRoot(makeInitialData());
          await patchRoot({ bookmarks: next, groups: this.groups.slice(), settings: (st as any).settings } as Partial<StorageModel>);
          LOGW('BM', 'storage_unavailable：已重建存储并重试写入 bookmarks(update, keep settings)');
        } else { throw e; }
      }
      this.bookmarks = this.bookmarks.map(b => b.id === id ? { ...b, ...patch, updatedAt: now } : b);
    },
    async removeBookmark(id: string) {
      let root = await getRoot();
      if (!root) { await setRoot(makeInitialData()); root = await getRoot(); }
      const r = root as StorageModel;
      const next = (Array.isArray(r.bookmarks) ? r.bookmarks : []).filter(b => b.id !== id);
      try {
        await patchRoot({ bookmarks: next } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const st = useSettings();
          await setRoot(makeInitialData());
          await patchRoot({ bookmarks: next, groups: this.groups.slice(), settings: (st as any).settings } as Partial<StorageModel>);
          LOGW('BM', 'storage_unavailable：已重建存储并重试写入 bookmarks(remove, keep settings)');
        } else { throw e; }
      }
      this.bookmarks = this.bookmarks.filter(b => b.id !== id);
    },

    // 拖拽排序（组内/跨组）
    reorderDebounced: debounce(async function persistReorder(this: any) {
      try {
        await patchRoot({ bookmarks: plain(this.bookmarks), groups: this.groups.slice() } as Partial<StorageModel>);
      } catch (e) {
        try{ (window as any).gceToast?.('⚠️ 排序保存失败'); }catch{}
        LOGE('BM', '排序保存失败', e as any);
        throw e;
      }
    }, 200),

    async persistNow() {
      try {
        await patchRoot({ bookmarks: plain(this.bookmarks), groups: this.groups.slice() } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const st = useSettings();
          await setRoot(makeInitialData());
          await patchRoot({ bookmarks: plain(this.bookmarks), groups: this.groups.slice(), settings: (st as any).settings } as Partial<StorageModel>);
          LOGW('BM', 'storage_unavailable：已重建存储并重试写入 bookmarks(persistNow, keep settings)');
        } else { throw e; }
      }
    },

    async reorderWithinGroup(groupId: string, idsInOrder: string[]) {
      const snapshot: DragSnapshot = {
        bookmarks: this.bookmarks.map(b => ({ ...b })),
        groups: this.groups.map(g => ({ ...g })),
      };
      try {
        const list = this.bookmarks.map(b => ({ ...b }));
        let order = 10;
        for (const id of idsInOrder) {
          const idx = list.findIndex(b => b.id === id);
          if (idx >= 0) {
            // 只更新在当前分组中的书签的顺序，不强制设置groupId
            const currentGroupId = list[idx].groupId ?? 'default';
            if (currentGroupId === groupId) {
              list[idx].order = order;
              list[idx].updatedAt = Date.now();
              order += 10;
            }
          }
        }
        this.bookmarks = list;
        await this.persistNow();
      } catch (e) {
        this.bookmarks = snapshot.bookmarks;
        this.groups = snapshot.groups;
        throw new Error(this.errorMsg);
      }
    },

    async moveToGroup(bookmarkId: string, targetGroupId: string, targetIndex?: number) {
      // 验证输入参数
      if (!bookmarkId || typeof bookmarkId !== 'string') {
        throw new Error('无效的书签ID');
      }
      if (!targetGroupId || typeof targetGroupId !== 'string') {
        throw new Error('无效的目标分组ID');
      }
      
      const snapshot: DragSnapshot = {
        bookmarks: this.bookmarks.map(b => ({ ...b })),
        groups: this.groups.map(g => ({ ...g })),
      };
      
      try {
        // 查找书签
        const bookmarkIndex = this.bookmarks.findIndex(b => b.id === bookmarkId);
        if (bookmarkIndex === -1) {
          throw new Error('书签不存在');
        }
        
        // 验证目标分组存在（或为默认分组）
        if (targetGroupId !== 'default') {
          const targetGroup = this.groups.find(g => g.id === targetGroupId);
          if (!targetGroup) {
            throw new Error('目标分组不存在');
          }
        }
        
        // 获取当前书签信息
        const currentBookmark = this.bookmarks[bookmarkIndex];
        const oldGroupId = currentBookmark.groupId ?? 'default';
        
        // 如果已经在目标分组，不需要移动
        if (oldGroupId === targetGroupId) {
          return;
        }
        
        // 一次性重建整个书签数组，确保响应式更新
        const newBookmarks = this.bookmarks.map(b => ({ ...b })); // 深拷贝
        
        // 更新目标书签的分组
        const targetBookmark = newBookmarks.find(b => b.id === bookmarkId)!;
        targetBookmark.groupId = targetGroupId === 'default' ? undefined : targetGroupId;
        targetBookmark.updatedAt = Date.now();
        
        // 重新排序原分组（去掉移动的书签）
        const sourceBookmarks = newBookmarks
          .filter(b => (b.groupId ?? 'default') === oldGroupId && b.id !== bookmarkId)
          .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
        
        sourceBookmarks.forEach((b, index) => {
          b.order = (index + 1) * 10;
        });
        
        // 重新排序目标分组（包括移动的书签）
        const targetBookmarks = newBookmarks
          .filter(b => (b.groupId ?? 'default') === targetGroupId)
          .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
        
        targetBookmarks.forEach((b, index) => {
          b.order = (index + 1) * 10;
        });
        
        // 一次性替换整个书签数组
        this.bookmarks = newBookmarks;
        
        // 写入存储 - 使用专用的书签更新（使用普通数组写入）
        try{
          await patchRoot({ bookmarks: plain(this.bookmarks), groups: this.groups.slice() } as Partial<StorageModel>);
        }catch(e:any){
          if (String(e?.message) === 'storage_unavailable'){
            const st = useSettings();
            await setRoot(makeInitialData());
            await patchRoot({ bookmarks: plain(this.bookmarks), groups: this.groups.slice(), settings: (st as any).settings } as Partial<StorageModel>);
            LOGW('BM', 'storage_unavailable：已重建存储并重试写入 bookmarks(moveToGroup, keep settings)');
          }else{ throw e; }
        }
        
      } catch (e) {
        // 恢复快照
        this.bookmarks = snapshot.bookmarks;
        this.groups = snapshot.groups;
        LOGE('BM', '跨组移动失败', e as any);
        throw e;
      }
    },
  }
});
